home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / initsprite / initsprite.c < prev    next >
C/C++ Source or Header  |  1993-01-06  |  10KB  |  387 lines

  1.  
  2. /*
  3.  * initsprite --
  4.  *
  5.  *    This program is the first user process execed by the Sprite kernel.
  6.  *
  7.  * Copyright 1988 Regents of the University of California
  8.  * Permission to use, copy, modify, and distribute this
  9.  * software and its documentation for any purpose and without
  10.  * fee is hereby granted, provided that the above copyright
  11.  * notice appear in all copies.  The University of California
  12.  * makes no representations about the suitability of this
  13.  * software for any purpose.  It is provided "as is" without
  14.  * express or implied warranty.
  15.  */
  16.  
  17. #ifndef lint
  18. static char rcsid[] = "$Header: /sprite/src/cmds/initsprite/RCS/initsprite.c,v 1.11 93/01/02 20:20:41 jhh Exp Locker: shirriff $ SPRITE (Berkeley)";
  19. #endif not lint
  20.  
  21. #include "option.h"
  22. #include <sprite.h>
  23. #include <errno.h>
  24. #include <fs.h>
  25. #include <fsCmd.h>
  26. #include <host.h>
  27. #include <signal.h>
  28. #include <status.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <sysStats.h>
  33. #include <sys/file.h>
  34. #include <sys/param.h>
  35. #include <sys/wait.h>
  36.  
  37. /*
  38.  * Initial input/output device to open.
  39.  */
  40. #define CONSOLE        "/dev/console"
  41.  
  42. /*
  43.  * Command script to execute after doing bare-bones initialization.
  44.  * If a host-dependent script exists, it is used in preference to
  45.  * this one.
  46.  */
  47. #define BOOTCMDS    "/boot/bootcmds"
  48.  
  49. /*
  50.  * Program to exec if we're coming up single user.
  51.  */
  52. char    login[]    =        "login";
  53.  
  54. /*
  55.  *  Command that was used to boot the machine.
  56.  */
  57. char            *bootCommand = NULL;
  58.  
  59. /*
  60.  * TRUE => run a login after initial setup.
  61.  */
  62. Boolean            singleUser = FALSE;
  63.  
  64. /*
  65.  * TRUE => check any disks
  66.  */
  67. Boolean            checkDisk = TRUE;
  68.  
  69. int        dummy;
  70.  
  71. Option    optionArray[] = {
  72.     {OPT_STRING, "b", (Address) &bootCommand, "Boot string passed to prom."},
  73.     {OPT_TRUE, "s", (Address) &singleUser, "Boot single-user mode."},
  74.     {OPT_FALSE, "f", (Address) &checkDisk, "Don't check disks (fastboot)."},
  75.     {OPT_TRUE, "root", (Address) &dummy, "Used by kernel, but not initsprite."},
  76.     {OPT_TRUE, "nonroot", (Address) &dummy, 
  77.         "Used by kernel, but not initsprite."},
  78.     {OPT_STRING, "rootdisk", (Address) &dummy, 
  79.         "Used by kernel, but not initsprite."},
  80. };
  81. int numOptions = sizeof(optionArray) / sizeof(Option);
  82.  
  83. /*
  84.  *----------------------------------------------------------------------
  85.  *
  86.  * Exec --
  87.  *
  88.  *    Utility procedure to run a command and wait for the child
  89.  *    to exit.
  90.  *
  91.  * Results:
  92.  *    Returns 0 if all went well, -1 otherwise.
  93.  *
  94.  * Side effects:
  95.  *    Prints a message if an error occurs.
  96.  *
  97.  *----------------------------------------------------------------------
  98.  */
  99.  
  100. int
  101. Exec(name, argv)
  102.     char *name;            /* Name of file to exec. */
  103.     char **argv;        /* Null-terminated array of arguments. */
  104. {
  105.     int pid, childPid;
  106.     union wait status;
  107.  
  108.     pid = fork();
  109.     if (pid == 0) {
  110.     execvp(name, argv);
  111.     _exit(1);
  112.     }
  113.     if (pid < 0) {
  114.     fprintf(stderr,
  115.         "Initsprite couldn't fork child for \"%s\": %s\n",
  116.         name, strerror(errno));
  117.     return -1;
  118.     }
  119.     childPid = wait(&status);
  120.     if (childPid < 0) {
  121.     fprintf(stderr,
  122.         "Initsprite couldn't wait for \"%s\": %s\n",
  123.         name, strerror(errno));
  124.     return -1;
  125.     }
  126.     if (childPid != pid) {
  127.     fprintf(stderr, "Initsprite waited for child 0x%x, got child 0x%x.\n",
  128.         pid, childPid);
  129.     return -1;
  130.     }
  131.     if (WIFSTOPPED(status)) {
  132.     fprintf(stderr, "Initsprite child \"%s\" stopped instead of exiting.\n",
  133.         name);
  134.     return -1;
  135.     }
  136.     if (status.w_retcode != 0) {
  137.     return -1;
  138.     }
  139.     return 0;
  140. }
  141.  
  142. /*
  143.  *----------------------------------------------------------------------
  144.  *
  145.  * main --
  146.  *
  147.  *    Main program for first user process in Sprite.
  148.  *
  149.  * Results:
  150.  *    Never returns.
  151.  *
  152.  * Side effects:
  153.  *    Lots.  Read the code..
  154.  *
  155.  *----------------------------------------------------------------------
  156.  */
  157.  
  158. main(argc, argv)
  159.     int        argc;         /* Number of arguments */
  160.     char    **argv;        /* Arguments */
  161. {
  162.     char            *argArray[20];
  163.     static struct sigvec    action = {SIG_IGN, 0, 0};
  164.     static char            string[200];
  165.     static char            name[MAXHOSTNAMELEN];
  166.     static char            hostID[10];
  167.     int                i;
  168.     int                status;
  169.     int                argsReturned;
  170.     static char            hostMachType[50];
  171.     char            pathname[MAXPATHLEN];
  172.     Host_Entry             *hostInfo;
  173.     Fs_Prefix            prefix;
  174.     Host_Entry             *rootInfo;
  175.     int                spriteID;
  176.     struct stat         statbuf;
  177.  
  178.  
  179.  
  180.     argsReturned = Opt_Parse(argc, argv, optionArray, numOptions, 0);
  181.  
  182.     /*
  183.      * Try to access the local boot directory. If it exists, then
  184.      * we have a local disk and we have to look for everything relative to
  185.      * the prefix. Otherwise we look relative to /.
  186.      */
  187.     /*
  188.      * Open the console which will in turn get inherited as stdin etc.
  189.      * by the shells that are forked.  After this, stdio can be used
  190.      * for I/O.  If this fails, exit with status 2 to indicate what
  191.      * happened (can't print a message, since there's no I/O yet).
  192.      */
  193.  
  194.     if ((open(CONSOLE, O_RDONLY, 0) != 0)
  195.         || (open(CONSOLE, O_WRONLY, 0) != 1)
  196.         || (open(CONSOLE, O_WRONLY, 0) != 2)) {
  197.     Test_PrintOut("Initsprite couldn't open console %s: %s\n",
  198.         CONSOLE, strerror(errno));
  199.     exit(2);
  200.     }
  201.     if (getwd(pathname) == 0) {
  202.     printf("Couldn't get working directory: %s\n", pathname);
  203.     } else {
  204.     printf("%s/%s starting up.\n", pathname, argv[0]);
  205.     }
  206.     if (argsReturned > 1) {
  207.     Opt_PrintUsage(argv[0], optionArray, Opt_Number(optionArray));
  208.     }
  209.     /*
  210.      * Set up signal actions.
  211.      */
  212.  
  213.     if (sigvec(SIGINT, &action, (struct sigvec *) NULL) != 0) {
  214.     fprintf(stderr,
  215.         "Warning: initsprite can't ignore SIGINT signals: %s\n", 
  216.         strerror(errno));
  217.     }
  218.     if (sigvec(SIGQUIT, &action, (struct sigvec *) NULL) != 0) {
  219.     fprintf(stderr,
  220.         "Warning: initsprite can't ignore SIGQUIT signals: %s\n",
  221.         strerror(errno));
  222.     }
  223.     if (sigvec(SIGHUP, &action, (struct sigvec *) NULL) != 0) {
  224.     fprintf(stderr,
  225.         "Warning: initsprite can't ignore SIGHUP signals: %s\n",
  226.         strerror(errno));
  227.     }
  228.     if (sigvec(SIGTERM, &action, (struct sigvec *) NULL) != 0) {
  229.     fprintf(stderr,
  230.         "Warning: initsprite can't ignore SIGTERM signals: %s\n",
  231.         strerror(errno));
  232.     }
  233.     /*
  234.      * Set up the environment.
  235.      */
  236.  
  237.     status = Proc_GetHostIDs((int *) NULL, &spriteID);
  238.     if (status != SUCCESS) {
  239.     fprintf(stderr, "Initsprite couldn't get host ID: %s\n",
  240.         Stat_GetMsg(status));
  241.     goto exitError;
  242.     }
  243.     /*
  244.      * If /.init exists then we have to run the configuration script
  245.      * first.
  246.      */
  247.     if (access("/.init", F_OK) == 0) {
  248.     if (Host_SetFile("/etc/spritehosts.init")) {
  249.         fprintf(stderr, "Couldn't set host file\n");
  250.     }
  251.     hostInfo = Host_ByID(spriteID);
  252.     Host_End();
  253.     if (hostInfo == NULL) {
  254.         fprintf(stderr,
  255.             "Initsprite can't get information about host %d: %s\n",
  256.             spriteID, strerror(errno));
  257.         goto exitError;
  258.     }
  259.     setenv("MACHINE", hostInfo->machType);
  260.     argArray[0] = "csh";
  261.     argArray[1] = "-f";
  262.     argArray[2] = "/boot/configsys";
  263.     argArray[3] = 0;
  264.     if (Exec("csh", argArray)) {
  265.         fprintf(stderr, "Can't run configuration script\n");
  266.     } else {
  267.         unlink("/.init");
  268.     }
  269.     if (Host_SetFile("/etc/spritehosts")) {
  270.         fprintf(stderr, "Couldn't set host file\n");
  271.     }
  272.     }
  273.     hostInfo = Host_ByID(spriteID);
  274.     if (hostInfo == NULL) {
  275.     fprintf(stderr,
  276.         "Initsprite can't get information about host %d: %s\n",
  277.         spriteID, strerror(errno));
  278.     goto exitError;
  279.     }
  280.     strncpy(name, hostInfo->name, MAXHOSTNAMELEN);
  281.     strncpy(hostMachType, hostInfo->machType, 50);
  282.     sprintf(hostID, "%d", hostInfo->id);
  283.     Host_End();
  284.     setenv("HOST", name);
  285.     setenv("MACHINE", hostMachType);
  286.     sprintf(string, ".:./cmds:/sprite/cmds.%.50s:/sprite/cmds", hostMachType);
  287.     setenv("PATH", string);
  288.     setenv("HOME", "/");
  289.     setenv("USER", "root");
  290.  
  291.     status = Sys_SetHostName(name);
  292.     if (status != SUCCESS) {
  293.     /*
  294.      * Ignore the error if the system call was invalid. Assume we are
  295.      * running on an old kernel.
  296.      */
  297.     if (status != SYS_INVALID_SYSTEM_CALL) {
  298.         fprintf(stderr, "Initsprite couldn't set host name: %s\n",
  299.         Stat_GetMsg(status));
  300.     }
  301.     }
  302.     if (singleUser) {
  303.     /*
  304.      *    If we are coming up single user then go to a login.
  305.      */
  306.     fprintf(stderr,"Single user mode requires root password.\n");
  307.     argArray[0] = "login";
  308.     argArray[1] = "-d";
  309.     argArray[2] = CONSOLE;
  310.     argArray[3] = "-l";
  311.     argArray[4] = "root";
  312.     argArray[5] = "-t";
  313.     argArray[6] = 0;
  314.     status = Exec(login, argArray);
  315.     if (status != 0) {
  316.         argArray[0] = "csh";
  317.         argArray[1] = "-i";
  318.         argArray[2] = 0;
  319.         status = Exec("csh", argArray);
  320.     }
  321.     if (status != 0) {
  322.         fprintf(stderr, "Can't run a shell.\n");
  323.     }
  324.     fprintf(stderr,"Initsprite continuing.\n");
  325.     }
  326.     /*
  327.      * Find the root server.
  328.      */
  329.     status = SUCCESS;
  330.     for (i = 0; status == SUCCESS; i++) {
  331.     bzero((char *) &prefix, sizeof(Fs_Prefix));
  332.     status = Sys_Stats(SYS_FS_PREFIX_STATS, i, (Address) &prefix);
  333.     if (status == SUCCESS) {
  334.         if (!strcmp(prefix.prefix, "/")) {
  335.         rootInfo = Host_ByID(prefix.serverID);
  336.         setenv("ROOTSERVER", rootInfo->name);
  337.         break;
  338.         }
  339.     }
  340.     }
  341.     /*
  342.      * If there is a bootcmds file in
  343.      * the host-specific directory, execute it instead of the one in /.
  344.      * Remember that the /.cshrc file will also be loaded by csh when
  345.      * processing bootcmds.
  346.      */
  347.  
  348.     sprintf(string, "/hosts/%.50s/bootcmds", name);
  349.     if (access(string, R_OK) != 0) {
  350.     strcpy(string, BOOTCMDS);
  351.     }
  352.     fprintf(stderr, "Executing %s\n", string);
  353.     i = 0;
  354.     argArray[i++] = "csh";
  355.     argArray[i++] = string;
  356.     if (bootCommand != NULL) {
  357.     argArray[i++] = "-b";
  358.     argArray[i++] = bootCommand;
  359.     }
  360.     if (!checkDisk) {
  361.     argArray[i++] = "-f";
  362.     }
  363.     argArray[i++] = "-i";
  364.     argArray[i++] = hostID;
  365.     argArray[i++] = 0;
  366.     if (Exec("csh", argArray) == 0) {
  367.     exit(0);
  368.     }
  369.     /*
  370.      * The boot command script did not complete successfully.  
  371.      * Try to bail out to a shell.
  372.      */
  373.  
  374.     fprintf(stderr, "Initsprite: boot command file exited abnormally!\n");
  375.  
  376.     argArray[0] = "csh";
  377.     argArray[1] = "-i";
  378.     argArray[2] = 0;
  379.     execvp("csh", argArray);
  380.     fprintf(stderr, "Init failed when trying to bailout to csh: %s\n",
  381.         strerror(errno));
  382.     fprintf(stderr, "Init has run out of things to try:  nothing works.\n");
  383. exitError:
  384.     fprintf(stderr, "Initsprite exiting.\n");
  385.     exit(1);
  386. }
  387.